#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string>
#include <fcntl.h>
#include <ctype.h>
#define COMMD_SIZE 1024
#define FORMAT "[%s@%s %s]#"

//命令行参数
#define MAX 128
int g_argc=0;
char* g_argv[MAX];


//  环境变量表
#define MAX_ENVS 100
char *g_env[MAX_ENVS];
int g_envs = 0;

//退出码
int lastcode=0;
//获取环境变量 
const char* GetUserName()
{
  const char* name=getenv("USER");
  return name==NULL?"None":name;
}
const char* GetHostName()
{
  const char* hostname=getenv("HOSTNAME");
  return hostname==NULL?"None":hostname;
}
char cwd[1024];
char cwdenv[1024];
const char* GetPwd()
{
 // const char* pwd=getenv("PWD");
  const char* pwd=getcwd(cwd,sizeof(cwd));
  if(pwd!=NULL)
  {
    snprintf(cwdenv,sizeof(cwdenv),"PWD=%s",cwd);
    putenv(cwdenv);
  }
  return pwd==NULL?"None":pwd;
}

const char* Gethome()
{
  const char* Home=getenv("HOME");
  return Home;
}

std::string DirName(char const* pwd)
{
#define SLASH "/"
  std::string dir=pwd;
  if(dir==SLASH)
    return SLASH;

  auto pos=dir.rfind(SLASH);
  if(pos==std::string::npos)
    return "BUG?";
      
  return dir.substr(pos+1);
}

void makecommdline(char promat[],int size)
{
   // snprintf(promat,size,FORMAT,GetUserName(),GetHostName(),DirName(GetPwd()).c_str());
    snprintf(promat,size,FORMAT,GetUserName(),GetHostName(),GetPwd());
}


//打印命令行
void printcommandline()
{
   char promat[COMMD_SIZE];
   makecommdline(promat,sizeof(promat));
   printf("%s",promat);
   fflush(stdout);
}

bool Getcommdline(char* out,int size)
{
   char* c=fgets(out,size,stdin);
   if(c==NULL)
     return false;
   out[strlen(out)-1]=0;
   if(strlen(out)==0)
     return false;

   return true;
}

//命令行解析
bool commdparse(char* commdline)
{
#define SEP " "
  g_argc=0;
  g_argv[g_argc++]=strtok(commdline,SEP);
  while((bool)(g_argv[g_argc++]=strtok(NULL,SEP)));
  g_argc--;
  return g_argc>0?true:false;
}

void printargv()
{ 
   for(int i=0;i<g_argc;i++)
     printf("g_argv[%d]->%s\n",i,g_argv[i]);
   printf("g_argc:%d\n",g_argc);
}

void Cd()
{
  //cd 
  if(g_argc==1)
  {
    std::string home=Gethome();
    chdir(home.c_str());
  }
  else 
  {
    std::string where=g_argv[1];
    //cd -//cd ~
    if(where=="-")
    {

    }
    else if(where=="~")
    {

    }
    else 
    {
      chdir(where.c_str());
    }
  }
}
void Echo()
{
  if(g_argc==2)
  {
    //echo "hello world"
    //echo $?
    //exho $PATH
    std::string opt=g_argv[1];
    if(opt=="$?")
    {
        std::cout<<lastcode<<std::endl;
    }
    else if(opt[0]=='$')
    {
      std::string env_name=opt.substr(1);
      const char* env_value=getenv(env_name.c_str());
      std::cout<<env_value<<std::endl;
    }
    else 
    {
      std::cout<<opt<<std::endl;
    }
  }
}
//处理内键命令
bool CheckecBuliting()
{
  std::string cmd=g_argv[0];
  if(cmd=="cd")
  {
     Cd();
     return true;
  }
  else if(cmd=="echo")
  {
      Echo();
  }
  else if(cmd=="export")
  {

  }
  else if(cmd=="alias")
  {

  }

  return false;
}

//重定4向
#define NONE_REDIR 0
#define INPUT_REDIR 1
#define OUTPUT_REDIR 2
#define APPEND_REDIR 3

std::string file;
int redir=NONE_REDIR;
//执行命令
int  Execute()
{
  pid_t id=fork();
  if(id==0)
  {
    int fd=-1;
    //子进程检测重定向
    if(redir==INPUT_REDIR)
    {
        fd=open(file.c_str(),O_RDONLY);
        if(fd<0)
          exit(1);

        dup2(fd,0);
        close(fd);
    }
    else if(redir==OUTPUT_REDIR)
    {
        fd=open(file.c_str(),O_CREAT | O_WRONLY | O_TRUNC,0666);
        if(fd<0)
          exit(1);

        dup2(fd,1);
        close(fd);
    }
    else if(redir==APPEND_REDIR)
    {
      fd=open(file.c_str(),O_CREAT | O_WRONLY | O_APPEND,0666);
      if(fd<0)
        exit(1);

      dup2(fd,1);
      close(fd);
    }
    else {}

     execvp(g_argv[0],g_argv);
     exit(1);
  }
  int status=0;
  pid_t rid=waitpid(id,&status,0);
  (void)rid;
  lastcode=WEXITSTATUS(status);

  return 0;
}


void InitEnv()
{
  extern char** environ;
  memset(g_env,0,sizeof(g_env));
  g_envs=0;
   
  for(int i=0;environ[i];i++)
  {
    g_env[i]=(char*)malloc(strlen(environ[i])+1);
    strcpy(g_env[i],environ[i]);

    g_envs++;
  }
  g_env[g_envs++]=(char*)"xg=1234567";
  g_env[g_envs]=NULL;

  for(int i=0;g_env[i];i++)
    putenv(g_env[i]);
  environ=g_env;

}

void Trime(char cmd[],int& end)
{
  while(isspace(cmd[end]))
    cmd++;
}
void CheckRedir(char cmd[])
{
    redir=NONE_REDIR;
    file.clear();

    int start=0;
    int end=strlen(cmd)-1;

    while(end>start)
    {
      if(cmd[end]=='<')
      {
         cmd[end++]=0;
         redir=INPUT_REDIR;
         Trime(cmd,end);
         file=cmd+end;
         break;
      }
      else if(cmd[end]=='>')
      {
        if(cmd[end-1]=='>')
        {
           cmd[end-1]=0;
           redir=APPEND_REDIR;
        }
        else 
        {
           redir=OUTPUT_REDIR;
        }
        cmd[end++]=0;
        Trime(cmd,end);
        file=cmd+end;
        break;
      }
      else 
      {
        end--;
      }
    }
}
int main()
{
   InitEnv();
  while(1)
  {
  //1，输出命令行提示符
  printcommandline();

  //2,获取用户输入的命令
  char commdline[COMMD_SIZE];
  if(!Getcommdline(commdline,sizeof(commdline)))
    continue;

    //3,重定向分析
    CheckRedir(commdline);

  //4，命令行分析
 if(!commdparse(commdline))
   continue;
  //printargv();
  
  //5,检测是否是内键命令
 if(CheckecBuliting())
   continue;

  //6，执行命令
  Execute();
  }

  return 0;
}
